package com.neusoft.neuiotms.dcom.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.dcom.bean.ProjectUserBean;
import com.neusoft.neuiotms.dcom.converter.InstitutionsConverter;
import com.neusoft.neuiotms.dcom.converter.ResidentChangeLogConverter;
import com.neusoft.neuiotms.dcom.converter.ResidentUserConverter;
import com.neusoft.neuiotms.dcom.dto.InstitutionsDTO;
import com.neusoft.neuiotms.dcom.dto.OperationGroupDTO;
import com.neusoft.neuiotms.dcom.dto.ResidentChangeLogDTO;
import com.neusoft.neuiotms.dcom.dto.ResidentUserDTO;
import com.neusoft.neuiotms.dcom.model.Institutions;
import com.neusoft.neuiotms.dcom.model.InstitutionsUser;
import com.neusoft.neuiotms.dcom.model.OperationGroup;
import com.neusoft.neuiotms.dcom.model.ResidentChangeLog;
import com.neusoft.neuiotms.dcom.model.ResidentChangeUser;
import com.neusoft.neuiotms.dcom.model.ResidentUser;
import com.neusoft.neuiotms.dcom.repository.InstitutionsRepository;
import com.neusoft.neuiotms.dcom.repository.InstitutionsUserRepository;
import com.neusoft.neuiotms.dcom.repository.OperationGroupRepository;
import com.neusoft.neuiotms.dcom.repository.ResidentChangeLogRepository;
import com.neusoft.neuiotms.dcom.repository.ResidentUserRepository;
import com.neusoft.neuiotms.dcom.service.InstitutionsService;
import com.neusoft.neuiotms.dcom.service.OperationGroupService;
import com.neusoft.neuiotms.dcom.util.PermUtils;

@Service
public class InstitutionsServiceImpl implements InstitutionsService {

    @Autowired
    private InstitutionsRepository institutionsRepository;
    @Autowired
    private InstitutionsUserRepository institutionsUserRepository;
    @Autowired
    private InstitutionsConverter institutionsConverter;
    @Autowired
    private OperationGroupService operationGroupService;
    @Autowired
    private OperationGroupRepository operationGroupRepository;
    @Autowired
    private ResidentUserRepository residentUserRepository;
    @Autowired
    private ResidentUserConverter residentUserConverter;
    @Autowired
    private ResidentChangeLogRepository residentChangeLogRepository;
    @Autowired
    private ResidentChangeLogConverter residentChangeLogConverter;

    @Override
    public List<InstitutionsDTO> index(final Searchable searchable) {
        final List<Institutions> result = this.institutionsRepository.index(searchable);
        return this.institutionsConverter.toListDTO(result);
    }

    @Override
    public Page<InstitutionsDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<Institutions> result = this.institutionsRepository.page(searchable, pageable);
        return this.institutionsConverter.toPageDTO(result);
    }

    @Override
    public InstitutionsDTO create(final InstitutionsDTO dto) {

        final StringBuffer error = new StringBuffer();

        if ((null == dto.getResidents()) && (dto.getResidents().size() == 0)) {
            throw new UnitedException("至少设置一位驻场人员");
        }

        final List<String> residentUserNameArray =
                dto.getResidents().stream().map(it -> it.getUsername()).collect(Collectors.toList());

        for (final String username : residentUserNameArray) {
            final ResidentUser existed = this.residentUserRepository.findByUsername(username);
            if (null != existed) {
                error.append(existed.getName() + "已存在驻场单位" + "\n");
            }
        }

        if (StringUtils.isNotEmpty(error.toString())) {
            throw new UnitedException(error.toString());
        }

        // 校验每个机动人员只能属于一个单位
        if (null != dto.getUsers()) {
            dto.getUsers().stream().forEach(user -> {
                if (null != this.institutionsUserRepository.findByUsername(user.getUsername())) {
                    error.append(user.getName() + "已机动驻场在别的单位" + "\n");
                }
            });

        }

        if (StringUtils.isNotEmpty(error.toString())) {
            throw new UnitedException(error.toString());
        }

        final Institutions model = this.institutionsConverter.toModel(dto);
        this.institutionsRepository.save(model);
        return this.institutionsConverter.toDTO(model);
    }

    @Override
    @Transactional
    public InstitutionsDTO update(final Long id, final InstitutionsDTO dto) {
        final StringBuffer error = new StringBuffer();
        Institutions model;
        try {
            model = this.institutionsRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        final List<ResidentUserDTO> oldResidents = this.residentUserConverter.toListDTO(model.getResidents());

        if ((null == dto.getResidents()) && (dto.getResidents().size() == 0)) {
            throw new UnitedException("至少设置一位驻场人员");
        }

        final List<String> residentUserNameArray =
                dto.getResidents().stream().map(it -> it.getUsername()).collect(Collectors.toList());

        for (final String username : residentUserNameArray) {
            final ResidentUser existed = this.residentUserRepository.findByUsername(username);
            if ((null != existed) && (id != existed.getInstitutions().getId())) {
                error.append(existed.getName() + "已存在驻场单位" + "\n");
            }
        }

        if (StringUtils.isNotEmpty(error.toString())) {
            throw new UnitedException(error.toString());
        }

        // 校验每个人员职能属于一个单位
        if (null != dto.getUsers()) {
            dto.getUsers().stream().forEach(user -> {
                final InstitutionsUser institutionsUser =
                        this.institutionsUserRepository.findByUsername(user.getUsername());
                if ((null != institutionsUser) && (id != institutionsUser.getInstitutions().getId())) {
                    error.append(user.getName() + "已经在别的单位" + "\n");
                }
            });
        }

        if (StringUtils.isNotEmpty(error.toString())) {
            throw new UnitedException(error.toString());
        }

        dto.setId(model.getId());
        model = this.institutionsConverter.toModel(dto);
        this.institutionsRepository.save(model);

        boolean residentChanged = false;
        if (model.getResidents().size() != oldResidents.size()) {
            residentChanged = true;
        } else {
            for (final ResidentUser u : model.getResidents()) {
                if (!oldResidents.stream().filter(it -> it.getUsername().equals(u.getUsername())).findAny()
                        .isPresent()) {
                    residentChanged = true;
                    break;
                }
            }
        }
        if (residentChanged) {
            final ResidentChangeLog log = new ResidentChangeLog();
            final List<ResidentChangeUser> changedResidents = new ArrayList<>();
            oldResidents.stream().map(it -> {
                final ResidentChangeUser residentChangeUser = new ResidentChangeUser();
                residentChangeUser.setUsername(it.getUsername());
                residentChangeUser.setName(it.getName());
                residentChangeUser.setResidentChangeLog(log);
                return residentChangeUser;
            }).forEach(changedResidents::add);

            log.setInstitutions(model);
            log.setResidents(changedResidents);
            this.residentChangeLogRepository.save(log);
        }

        return this.institutionsConverter.toDTO(model);
    }

    @Override
    public InstitutionsDTO details(final Long id) {

        Institutions model;
        try {
            model = this.institutionsRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        return this.institutionsConverter.toDTO(model);
    }

    @Override
    public void delete(final Long id) {

        final Searchable searchable = new Searchable();
        searchable.put("institutionsId", id);
        final List<OperationGroupDTO> check = this.operationGroupService.index(searchable);

        if (check.size() > 0) {
            throw new UnitedException("该厅局已关联运维小组，请先删除关联关系");
        }

        this.institutionsRepository.deleteById(id);
    }

    @Override
    public ProjectUserBean getMyInstitutions(final UserBean user) {
        final ProjectUserBean bean = new ProjectUserBean();

        if (PermUtils.isWorker(user) || PermUtils.isBigdataBureau(user)) {
            final ResidentUser residentUser = this.residentUserRepository.findByUsername(user.getUsername());
            if (null == residentUser) {
                return bean;
            }

            final Institutions inst = residentUser.getInstitutions();

            if (null == inst) {
                return bean;
            }
            final OperationGroup group = this.operationGroupRepository.findByInstitutionsIn(Arrays.asList(inst));
            if (null == group) {
                return bean;
            }
            bean.setGroupCode(group.getCode());
            bean.setGroupName(group.getName());
            bean.setGroupLeader(group.getGroupLeaderCode());
            bean.setDefaultInstituteCode(inst.getCode());
            bean.setDefaultInstituteName(inst.getName());
            final List<Institutions> institutions = Lists.newArrayList(inst);
            bean.setInstitutions(this.institutionsConverter.toListDTO(institutions));
        } else if (PermUtils.isWorkerGroupLeader(user)) {
            final OperationGroup group = this.operationGroupRepository.findByGroupLeaderCode(user.getUsername());
            bean.setGroupCode(group.getCode());
            bean.setGroupLeader(group.getGroupLeaderCode());
            final List<Institutions> institutions = group.getInstitutions();
            bean.setInstitutions(this.institutionsConverter.toListDTO(institutions));

            if (institutions.size() > 0) {
                bean.setDefaultInstituteCode(institutions.get(0).getCode());
            }
        } else {
            final List<Institutions> institutions = this.institutionsRepository.findAll();
            bean.setInstitutions(this.institutionsConverter.toListDTO(institutions));
            if (institutions.size() > 0) {
                bean.setDefaultInstituteCode(institutions.get(0).getCode());
            }
        }
        return bean;
    }

    @Override
    public List<InstitutionsDTO> getPermInstitutions(final UserBean user) {
        List<Institutions> institutions = Lists.newArrayList();
        if (PermUtils.isWorker(user) || PermUtils.isBigdataBureau(user)) {
            final ResidentUser residentUser = this.residentUserRepository.findByUsername(user.getUsername());
            if (null != residentUser) {
                // 1，找到自己驻场的厅局
                final Institutions inst = residentUser.getInstitutions();
                institutions.add(inst);
            }

        } else if (PermUtils.isWorkerGroupLeader(user)) {
            final OperationGroup group = this.operationGroupRepository.findByGroupLeaderCode(user.getUsername());
            institutions = group.getInstitutions();
        } else if (PermUtils.isBackup(user) || PermUtils.isZongjian(user) || PermUtils.isAdmin(user)) {
            institutions.addAll(this.institutionsRepository.findAll());
        } else if (PermUtils.isExport(user) || PermUtils.isExpertGroupLeader(user)) {
            institutions.addAll(this.institutionsRepository.findAll());
        }

        return this.institutionsConverter.toListDTO(institutions);
    }

    @Override
    public List<ResidentChangeLogDTO> getResidentChangeLogs(final Long institutionId) {
        final List<ResidentChangeLog> logs =
                this.residentChangeLogRepository.findByInstitutions_IdOrderByChangeAtDesc(institutionId);
        return this.residentChangeLogConverter.toListDTO(logs);
    }
}
